package org.example.rabbitmq.client.concurrent;

import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;

import java.util.function.Function;

public class DynamicMessageListenerContainerBuilder {
    DynamicMessageListenerContainerLifecycle containerLifecycle = new DynamicMessageListenerContainerLifecycle();

    private int queueSize;
    private int concurrentConsumers = 1;
    private Function<Integer, String> queueNameGenerator;
    private Function<Integer, String> routingKeyGenerator;

    public static DynamicMessageListenerContainerBuilder create() {
        return new DynamicMessageListenerContainerBuilder();
    }

    public DynamicMessageListenerContainerBuilder queueSize(int queueSize) {
        this.queueSize = queueSize;
        return this;
    }

    public DynamicMessageListenerContainerBuilder concurrentConsumers(int concurrentConsumers) {
        this.concurrentConsumers = concurrentConsumers;
        return this;
    }

    public DynamicMessageListenerContainerBuilder withQueueNameGenerator(Function<Integer, String> queueNameGenerator) {
        this.queueNameGenerator = queueNameGenerator;
        return this;
    }

    public DynamicMessageListenerContainerBuilder withRoutingKeyGenerator(Function<Integer, String> routingKeyGenerator) {
        this.routingKeyGenerator = routingKeyGenerator;
        return this;
    }

    public DynamicMessageListenerContainerBuilder initializeQueueAndBinding(RabbitAdmin rabbitAdmin, String exchangeName) {
        for (int i = 1; i <= queueSize; i++) {
            String queueName = queueNameGenerator.apply(i);
            rabbitAdmin.declareQueue(new Queue(queueName, true, false, false));
            String routingKey = routingKeyGenerator.apply(i);
            rabbitAdmin.declareBinding(new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, routingKey, null));
        }
        return this;
    }

    public DynamicMessageListenerContainerBuilder initializeQueue(RabbitAdmin rabbitAdmin) {
        for (int i = 1; i <= queueSize; i++) {
            String queueName = queueNameGenerator.apply(i);
            rabbitAdmin.declareQueue(new Queue(queueName, true, false, false));
        }
        return this;
    }

    public DynamicMessageListenerContainerBuilder bindingQueue(RabbitAdmin rabbitAdmin, String exchangeName) {
        for (int i = 1; i <= queueSize; i++) {
            String queueName = queueNameGenerator.apply(i);
            String routingKey = routingKeyGenerator.apply(i);
            rabbitAdmin.declareBinding(new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, routingKey, null));
        }
        return this;
    }

    public DynamicMessageListenerContainerBuilder initializeContainer(ConnectionFactory connectionFactory, ChannelAwareMessageListener messageListener) {
        for (int i = 1; i <= queueSize; i++) {
            String queueName = queueNameGenerator.apply(i);
            registerContainer(connectionFactory, messageListener, AcknowledgeMode.MANUAL, queueName);
        }
        return this;
    }

//    public DynamicContainerBuilder initContainer(ConnectionFactory connectionFactory, MessageListener messageListener, AcknowledgeMode mode) {
//        for (int i = 1; i <= queueSize; i++) {
//            String queueName = queueNameGenerator.apply(i);
//            registerContainer(connectionFactory, messageListener, mode, queueName);
//        }
//        return this;
//    }

    private void registerContainer(ConnectionFactory connectionFactory, ChannelAwareMessageListener messageListener, AcknowledgeMode mode, String... queueNames) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        container.setQueueNames(queueNames);
        container.setMessageListener(messageListener);
        container.setConcurrentConsumers(concurrentConsumers);
        container.setAcknowledgeMode(mode);
        containerLifecycle.addContainer(container);
    }

    public DynamicMessageListenerContainerLifecycle build() {
        return containerLifecycle;
    }
}